﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; 

namespace ICSharpCode.WinFormsUI.Controls.Chart3D
{
    public class Vector3D
    {
        public Vertex point1;
        public Vertex point2;

        public double X, Y, Z = 0;

        public Vector3D(double x, double y, double z)
        {
            this.X = x;
            this.Y = y;
            this.Z = z;
        }

        public Vector3D(double x1, double y1, double z1, double x2, double y2, double z2)
        {
            this.point1 = new Vertex((float)x1, (float)y1, (float)z1);
            this.point2 = new Vertex((float)x2, (float)y2, (float)z2);
            this.X = point2.X - point1.X;
            this.Y = point2.Y - point1.Y;
            this.Z = point2.Z - point1.Z;
        }

        public Vector3D(Vertex pt1, Vertex pt2)
            : this(pt1.X, pt1.Y, pt1.Z, pt2.X, pt2.Y, pt2.Z)
        {
            //
        }

        /// <summary>
        /// 返回向量的模(长度)（只读）
        /// </summary>
        public double Magnitude
        {
            get { return Math.Sqrt(X * X + Y * Y + Z * Z); }
        }

        /// <summary>
        /// 向量规范化：就是让向量的长度等于1;  
        /// </summary>
        public void Normalized()
        {
            double m = Math.Sqrt(X * X + Y * Y + Z * Z);
            if (m > 0.001)
            {
                X /= m; Y /= m; Z /= m;
            }
        }

        public static Vector3D operator +(Vector3D v1, Vector3D v2)
        {
            return new Vector3D(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
        }

        public static Vector3D operator -(Vector3D v1, Vector3D v2)
        {
            return new Vector3D(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
        }

        public static Vector3D operator -(Vector3D v)
        {
            return new Vector3D(-v.X, -v.Y, -v.Z);
        }

        public static Vector3D operator +(Vector3D v)
        {
            return new Vector3D(v.X, v.Y, v.Z);
        }
                
        /// <summary>
        /// 3D向量叉积
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public Vector3D CrossProduct(Vector3D v)
        {
            return CrossProduct(this, v);
        }

        // A x B = |A|*|B|*sin(angle), direction follow right-hand rule
        // 3D向量叉积
        public static Vector3D CrossProduct(Vector3D v1, Vector3D v2)
        {
            return new Vector3D(v1.Y * v2.Z - v1.Z * v2.Y, v1.Z * v2.X - v1.X * v2.Z, v1.X * v2.Y - v1.Y * v2.X);
        }

        /// <summary>
        /// 3D向量点积
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        public double DotProduct(Vector3D v)
        {
            return DotProduct(this, v);
        }

        // A . B = |A|*|B|*cos(angle)
        //3D向量点积
        public static double DotProduct(Vector3D v1, Vector3D v2)
        {
            return (v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z);
        }

        /// <summary>
        /// 判断是否前面，看得见的一面
        /// </summary>
        /// <param name="pt1"></param>
        /// <param name="pt2"></param>
        /// <param name="pt3"></param>
        /// <returns></returns>
        public static bool isForeFace(Vertex pt1, Vertex pt2, Vertex pt3) // pts on a plane
        {
            Vector3D v1 = new Vector3D(pt2, pt1);
            Vector3D v2 = new Vector3D(pt2, pt3);
            Vector3D v = v1.CrossProduct(v2);
            return v.DotProduct(new Vector3D(0, 0, 1)) < 0;
        }

        /// <summary>
        /// 判断是否背面，看不见的一面
        /// </summary>
        /// <param name="pt1"></param>
        /// <param name="pt2"></param>
        /// <param name="pt3"></param>
        /// <returns></returns>
        public static bool isBackFace(Vertex pt1, Vertex pt2, Vertex pt3)
        {
            Vector3D v1 = new Vector3D(pt2, pt1);
            Vector3D v2 = new Vector3D(pt2, pt3);
            Vector3D v = v1.CrossProduct(v2);
            return v.DotProduct(new Vector3D(0, 0, 1)) > 0;
        }


         

    }
}
